//
//  CLString+String.swift
//  Extensions
//
//  Created by gupengling on 2021/6/5.
//  Copyright © 2021 gupengling. All rights reserved.
//

import UIKit
import CommonCrypto

extension String: WDExtensionCompatible { }

public extension WDExtension where Base == String {
    public var md5: String {
        if let data = base.data(using: .utf8, allowLossyConversion: true) {
            let message = data.withUnsafeBytes { bytes -> [UInt8] in
                return Array(UnsafeBufferPointer(start: bytes, count: data.count))
            }
            let str = base.cString(using: String.Encoding.utf8)
            let strLen = CUnsignedInt(base.lengthOfBytes(using: String.Encoding.utf8))
            let digestLen = Int(CC_MD5_DIGEST_LENGTH)
            let result = UnsafeMutablePointer<CUnsignedChar>.allocate(capacity: digestLen)
            CC_MD5(str!, strLen, result)
            let hash = NSMutableString()
            for i in 0..<digestLen {
                hash.appendFormat("%02x", result[i])
            }
            result.deallocate()
            return hash as String

        } else {
            return base
        }
    }
    
    /// base64编码
    public var base64Encoding: WDExtension {
        let data = base.data(using:.utf8)
        let base64 = data?.base64EncodedString()
        return base64?.wd ?? self
    }
    /// base64解码
    public  var base64Decoding: WDExtension {
        guard let data = Data(base64Encoded: base) else {
            return self
        }
        let str = String(data: data , encoding: .utf8)
        return str?.wd ?? self
    }
}

public extension String {
    static func convert(fromJSON object: Any) -> String? {
        if JSONSerialization.isValidJSONObject(object) {
            if let data = try? JSONSerialization.data(withJSONObject: object, options: .prettyPrinted) {
                return String.init(data: data, encoding: .utf8)
            }
        }
        return nil
    }
    
    var length: Int {
        get {
            return self.count
        }
    }
    
    var firstPinyinLetter: String {
        get {
            return self.toPinyin().substring(to: 1)
        }
    }
    
    func toPinyin() -> String {
        let str = NSMutableString(string: self)
        CFStringTransform(str as CFMutableString, nil, kCFStringTransformMandarinLatin, false)
        CFStringTransform(str as CFMutableString, nil, kCFStringTransformStripDiacritics, false)
        let pinyin = str.capitalized
        return pinyin
    }
    
    var base64EncodedString: String? {
        get {
            let data = self.data(using: .utf8)
            return data?.base64EncodedString()
        }
    }
    
    var base64DecodedString: String? {
        get {
            if let data = Data(base64Encoded: self) {
                return String(data: data, encoding: .utf8)
            }
            return nil
        }
    }
    
    func toJsonObject() -> Any? {
        if let data = self.data(using: .utf8) {
            return try? JSONSerialization.jsonObject(with: data, options: .allowFragments)
        }
        return nil
    }
    
    func substring(from: Int) -> String {
        return self.substring(from: from, length: self.length - from)
    }
    
    func substring(to: Int) -> String {
        return self.substring(from: 0, length: to)
    }
    
    func substring(with range: NSRange) -> String {
        return self.substring(from: range.location, length: range.length)
    }
    
    func substring(from: Int, length: Int) -> String {
        let str = self as NSString
        var from = from
        if from < 0 {
            from = 0
        } else if from >= self.length {
            from = self.length - 1
        }
        var length = length
        if from + length > self.length {
            length = self.length - from
        }
        return str.substring(with: NSMakeRange(from, length))
    }
    
    func matches(_ regularExpression: String) -> Bool {
        let predicate = NSPredicate(format: "SELF MATCHES %@", regularExpression)
        return predicate.evaluate(with: self)
    }
    
    func boundingRect(with size: CGSize,
                      options: NSStringDrawingOptions,
                      attributes: [NSAttributedString.Key: Any]?,
                      context: NSStringDrawingContext?) -> CGRect {
        let str = self as NSString
        return str.boundingRect(with: size,
                                options: options,
                                attributes: attributes,
                                context: context)
    }
    
    /// Returns if String is a number
    func isNumber() -> Bool {
        return NumberFormatter().number(from: self) != nil ? true : false
    }
    
    /// Checks if String contains Emoji
    func includesEmoji() -> Bool {
        for i in 0...length {
            let c: unichar = (self as NSString).character(at: i)
            if (0xD800 <= c && c <= 0xDBFF) || (0xDC00 <= c && c <= 0xDFFF) {
                return true
            }
        }
        return false
    }
    
    // URL encode a string (percent encoding special chars)
    func urlEncoded() -> String {
        return self.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)!
    }
    
    // URL encode a string (percent encoding special chars) mutating version
    mutating func urlEncode() {
        self = urlEncoded()
    }
    
    // Removes percent encoding from string
    public func urlDecoded() -> String {
        return removingPercentEncoding ?? self
    }
    
    // Mutating versin of urlDecoded
    mutating func urlDecode() {
        self = urlDecoded()
    }
}

